package yogaService

import (
	"duoke/internal/dao"
	"duoke/model"
	"duoke/model/yogaModel"
	"duoke/service"
	"duoke/service/common"
	"duoke/tables"
	utils "duoke/utils/common"
	"duoke/utils/orm"
	"duoke/utils/redislib"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/gconv"
	"time"
)

var Order = new(orderService)

type orderService struct{}

func (s *orderService) CreateOrder(c *gin.Context, req *yogaModel.CreateOrder) (string, error) {
	user, err := service.User.Info(c, "*")
	if err != nil {
		return "", err
	}
	// 4. 结合分布式锁（高并发场景）
	lockKey := fmt.Sprintf("order_lock:user:%d:class:%d", user.Id, req.Id)
	locked := redislib.Redis.SetNX(c, lockKey, "locked", time.Second*10)
	if !locked.Val() {
		return "", errors.New("操作太频繁，请稍后再试")
	}
	defer redislib.Redis.Del(c, lockKey)
	// var order yogaModel.ReqOrder
	//where := fmt.Sprintf("from_id=%d and user_id=%d and state=2", req.Id, user.Id)
	//get, err := common.Tales.Info(where, "*").Table("yoga_order").Get(&order)
	//if err != nil {
	//	return "", err
	//}
	//if get {
	//	return order.OrderNo, nil
	//}
	// 查预约日期
	var yd yogaModel.ReqDate
	where := fmt.Sprintf("id=%d", req.Id)
	get, err := common.Tales.Info(where, "*").Table("yoga_date").Get(&yd)
	if err != nil {
		return "", err
	}
	// 查预约课程
	var gc yogaModel.ReqGroupClass
	where = fmt.Sprintf("id=%d", yd.ClassId)
	get, err = common.Tales.Info(where, "*").Table("yoga_group_class").Get(&gc)
	if err != nil {
		return "", err
	}
	if !get {
		return "", errors.New("该预约班课不存在")
	}
	// 判断预约人数
	if (gc.Contain - yd.AppointmentsNumber) < req.AppointmentsNumber {
		return "", errors.New("预约班课人数已满")
	}
	m := &tables.YogaOrder{
		FromId:             req.Id,
		UserId:             user.Id,
		Acid:               user.Acid,
		TotalAmount:        gc.Price,
		OrderNo:            utils.Common.GetOrder(),
		SubMchId:           gc.SubMchId,
		IpAddr:             user.IpAddr,
		Body:               "瑜伽预约",
		Openid:             user.Openid,
		State:              2,
		OrderType:          1,
		AppointmentRemarks: req.AppointmentRemarks,
		AppointmentsNumber: req.AppointmentsNumber,
		SeparateState:      2,
		ClassId:            gc.Id,
		BuyTime:            req.BuyTime,
		ClassName:          gc.Name,
	}
	// 创建订单
	insert, err := orm.Db.Table("yoga_order").Insert(m)
	if err != nil && insert <= 0 {
		return "", errors.New("创建订单失败")
	}
	return m.OrderNo, nil
}

func (s *orderService) OrderInfo(c *gin.Context, orderNo string) (*yogaModel.OrderInfo, error) {
	var m yogaModel.OrderInfo
	user, err := service.User.Info(c, "*")
	if err != nil {
		return nil, err
	}
	m.Score = user.Score
	// 查订单
	var order yogaModel.ReqOrder
	get, err := common.Tales.Info("order_no="+orderNo, "*").Table("yoga_order").Get(&order)
	if err != nil {
		return nil, err
	}
	if !get {
		return nil, errors.New("该订单不存在")
	}
	// 查预约课程
	where := fmt.Sprintf("yc.id=%d", order.ClassId)
	get, err = common.Tales.JoinInfo(where, "yc.id,yc.name,yc.class_type,yc.classroom,yc.difficulty,yc.duration,"+
		"yt.name as teacher_name,yc.price,yc.start_time,yc.end_time,yc.cover").Table("yoga_group_class as yc").
		Join("LEFT", "yoga_teacher as yt", "yc.teacher_id = yt.id").Get(&m.Class)
	if err != nil {
		return nil, err
	}
	if !get {
		return nil, errors.New("预约课程不存在")
	}
	// 查询该商户是否有开权限
	where = fmt.Sprintf("sub_mch_id='%s'", order.SubMchId)
	var yc yogaModel.ReqConfig
	get, err = common.Tales.Info(where, "*").Table("yoga_config").Get(&yc)
	if err != nil {
		return nil, err
	}
	if !get {
		return nil, errors.New("该小程序商户未配置权限")
	}
	m.AppointmentRemarks = order.AppointmentRemarks
	m.AppointmentsNumber = order.AppointmentsNumber
	m.BuyTime = order.BuyTime
	return &m, err
}

func (s *orderService) OrderAmount(c *gin.Context, req *yogaModel.PayOrder) (*yogaModel.ReqOrder, error) {
	// 先判断是否有未支付的订单
	var sub yogaModel.ReqOrderSub
	where := fmt.Sprintf("order_no='%s' and state=%d", req.OrderNo, 2)
	var order yogaModel.ReqOrder
	get, err := common.Tales.Info(where, "*").Table("yoga_order").Get(&order)
	if err != nil || !get {
		return nil, errors.New("该订单错误")
	}
	// 查询子表
	where = fmt.Sprintf("order_no='%s'", req.OrderNo)
	get, err = common.Tales.JoinInfo(where, "*").Table("yoga_order_sub").Get(&sub)
	if err != nil {
		return nil, errors.New("订单子表错误")
	}
	sub.Yprice = order.TotalAmount
	// 获取用户信息
	info, err := service.User.Info(c, "openid,score")
	if err != nil && info.Id <= 0 {
		return nil, errors.New("该用户不存在")
	}
	if req.Integral > info.Score {
		return nil, errors.New("积分不足")
	}
	// 获取该预约课程
	where = fmt.Sprintf("id=%d", order.ClassId)
	var gc yogaModel.ReqGroupClass
	get, err = common.Tales.JoinInfo(where, "*").Table("yoga_group_class").Get(&gc)
	if err != nil || !get {
		return nil, errors.New("该预约课程错误")
	}
	// 判断积分是否大于可抵扣积分
	if req.Integral > gc.Points {
		return nil, errors.New("积分大于可抵用积分")
	}
	// 获取该商户的配置信息
	where = fmt.Sprintf("sub_mch_id='%s'", gc.SubMchId)
	var yc yogaModel.ReqConfig
	get, err = common.Tales.Info(where, "*").Table("yoga_config").Get(&yc)
	if req.Integral != 0 {
		// 用户抵扣金额
		order.TotalAmount -= float32(req.Integral) / float32(yc.IntegralTransforms)
		sub.IntegralMoney = float32(req.Integral) / float32(yc.IntegralTransforms)
	}
	if req.CouponId != 0 {
		// 优惠券抵扣
		infos, err := service.Coupon.Infos(c, req.CouponId)
		if err != nil && len(infos) <= 0 {
			return nil, errors.New("优惠券错误")
		}
		m := infos[0]
		// type 1 满减需要判断
		if gconv.Int(m["type"]) == 1 {
			if gconv.Float32(m["man"]) > order.TotalAmount {
				return nil, errors.New("未达到该优惠券的使用门槛")
			}
			order.TotalAmount -= gconv.Float32(m["jian"])
			sub.CouponMoney = gconv.Float32(m["jian"])
		} else {
			order.TotalAmount *= 1 - (gconv.Float32(m["zhe"]) / 100)
			sub.CouponMoney = 1 - (gconv.Float32(m["zhe"]) / 100)
		}
	}
	// 插入订单子表
	sub.SubMchId = order.SubMchId
	sub.OrderNo = order.OrderNo
	sub.Integral = req.Integral
	sub.CouponId = req.CouponId
	sub.Price = order.TotalAmount
	sub.Acid = order.Acid
	if sub.Id == 0 {
		insert, err := orm.Db.Table("yoga_order_sub").Insert(&sub)
		if err != nil && insert <= 0 {
			return nil, errors.New("创建订单子表失败")
		}
	} else {
		insert, err := orm.Db.Table("yoga_order_sub").Where("id=?", sub.Id).Update(&sub)
		if err != nil && insert <= 0 {
			return nil, errors.New("修改订单子表失败")
		}
	}
	return &order, nil
}

func (s *orderService) MyOrder(c *gin.Context, y *yogaModel.ReqOrderList) (*[]yogaModel.ReqMyOrder, int64, error) {
	// 获取用户数据
	const TablesMyOrder = "yoga_my_order"
	user, err := service.Request.User(c)
	if err != nil && user.Id == 0 {
		return nil, 0, errors.New("获取用户信息错误")
	}
	where := fmt.Sprintf("user_id=%d and order_type=%d", user.Id, y.OrderType)
	if y.AppointmentStatus != 0 {
		where += fmt.Sprintf(" and appointment_status=%d", y.AppointmentStatus)
	}
	if y.SignType != 0 {
		where += fmt.Sprintf(" and sign_type=%d", y.SignType)
	}
	var m []yogaModel.ReqMyOrder
	count, err := common.Tales.Infos(c, &model.ReqListV2{
		PageSize: y.PageSize,
		PageNo:   y.PageNo,
	}, where, "*").Table(TablesMyOrder).Omit("total_amount").FindAndCount(&m)
	return &m, count, err
}

func (s *orderService) Reservation(c *gin.Context, y *yogaModel.ReqReservation) error {
	if y.Id == 0 {
		return errors.New("参数缺失【id】")
	}
	user, err := service.Request.User(c)
	const TablesMyOrder = "yoga_my_order"
	if err != nil || user.Id == 0 {
		return errors.New("获取用户数据失败")
	}
	// 查询该预约是否存在
	where := fmt.Sprintf("id=%d and user_id=%d", y.Id, user.Id)
	count, err := common.Tales.Info(where, "id").Table(TablesMyOrder).Count()
	if err != nil && count == 0 {
		return errors.New("该预约有误")
	}
	var m yogaModel.ReqMyOrder
	m.Id = y.Id
	if y.SignType == 0 && y.AppointmentStatus == 0 {
		return errors.New("参数缺失【sign_type/appointment_status】")
	}
	if y.SignType > 2 || y.AppointmentStatus > 2 {
		return errors.New("参数范围错误")
	}
	// 修改预约状态
	update, err := common.Tales.Info(where, "id,appointment_status,sign_type").Table(TablesMyOrder).Update(y)
	if err != nil || update == 0 {
		return errors.New("修改失败")
	}
	return err
}

func (s *orderService) OrderList(c *gin.Context, req *model.ReqListV2) (*[]yogaModel.RspOrderList, int64, error) {
	user, err := service.Request.User(c)
	if err != nil || user.Id == 0 {
		return nil, 0, errors.New("获取用户数据失败")
	}
	var m []yogaModel.RspOrderList
	const TablesOrder = "yoga_order"
	where := fmt.Sprintf("user_id=%d", user.Id)
	if req.State != 0 {
		where += fmt.Sprintf(" and state=%d", req.State)
	}
	count, err := common.Tales.Infos(c, req, where,
		"order_no,state,total_amount,pay_time,cover,class_type,start_time,end_time,yo.deleted_at,yo.created_at"+
			",yc.content,yc.name as class_name",
		"yo.id desc").Table(TablesOrder).Alias("yo").
		Join("LEFT", "yoga_group_class as yc", "yc.id = yo.class_id").
		FindAndCount(&m)

	for k := range m {
		// 使用gtime的Parser解析时间
		content := gtime.ParseTimeFromContent(m[k].CreatedAt, "Y-m-d H:i:s")
		m[k].CreatedAt = content.Format("Y-m-d H:i:s")
	}
	return &m, count, err
}

func (s *orderService) OrderDetail(c *gin.Context, req string) (*yogaModel.RspOrderInfo, error) {
	user, err := service.Request.User(c)
	if err != nil && user.Id == 0 {
		return nil, errors.New("获取用户数据失败")
	}
	const TablesOrder = "yoga_order"
	var m yogaModel.ReqOrder
	get, err := common.Tales.Info(fmt.Sprintf("order_no='%s' and user_id=%d", req, user.Id), "*").
		Table(TablesOrder).Get(&m)
	if !get || err != nil {
		return nil, errors.New("获取订单信息失败")
	}
	// 获取课程信息
	var Info yogaModel.RspOrderInfo
	where := fmt.Sprintf("yc.id=%d", m.ClassId)
	get, err = common.Tales.Info(where, "yc.id,yc.name,yc.cover,yc.price,yc.content,yv.name as venue_name,"+
		"yc.deleted_at,yc.start_time,yc.end_time").Table("yoga_group_class as yc").
		Join("LEFT", "yoga_venue as yv", "yc.venue_id = yv.id").
		Get(&Info)
	if !get || err != nil {
		return nil, errors.New("获取约课信息失败")
	}
	Info.OrderNo = m.OrderNo
	Info.TotalAmount = m.TotalAmount
	Info.CreatedAt = m.CreatedAt
	Info.State = m.State
	return &Info, err
}
func (s *orderService) List(c *gin.Context, req *yogaModel.SearchOrder) (*model.RspList, error) {
	session := dao.YogaOrder.Ctx(c)
	where := g.Map{}
	if req.OrderNo != "" {
		where["a.order_no = ?"] = req.OrderNo
	}
	if req.UserId != 0 {
		where["a.user_id = ?"] = req.UserId
	}
	if req.State != 0 {
		where["a.state = ?"] = req.State
	}
	var m []yogaModel.ReqSearchOrder
	var count int
	err := session.Where(where).OrderDesc("id").As("a").
		LeftJoin("user ", "b", "a.user_id=b.id").
		Fields("a.*", "b.nickname", "b.avatar").Page(req.PageNo, req.PageSize).
		ScanAndCount(&m, &count, false)
	if err != nil {
		return nil, err
	}
	for k, item := range m {
		item.PayTime = gconv.Int(item.PayTime)
		if item.PayTime != 0 {
			m[k].PayTime = gtime.New(item.PayTime).Format("Y-m-d H:i:s")
		} else {
			m[k].PayTime = ""
		}
	}
	return &model.RspList{
		List:  m,
		Total: int64(count),
	}, nil

}

func (s *orderService) CourseOrder(c *gin.Context, req *yogaModel.SearchOrder) (*model.RspList, error) {
	session := dao.YogaCourseOrder.Ctx(c)
	where := g.Map{}
	if req.OrderNo != "" {
		where["a.order_no = ?"] = req.OrderNo
	}
	if req.UserId != 0 {
		where["a.user_id = ?"] = req.UserId
	}
	if req.State != 0 {
		where["a.state = ?"] = req.State
	}
	var m []yogaModel.ReqSearchOrder
	var count int
	err := session.Where(where).OrderDesc("id").As("a").
		LeftJoin("user ", "b", "a.user_id=b.id").
		Fields("a.*", "b.nickname", "b.avatar").Page(req.PageNo, req.PageSize).
		ScanAndCount(&m, &count, false)
	if err != nil {
		return nil, err
	}
	for k, item := range m {
		item.PayTime = gconv.Int(item.PayTime)
		if item.PayTime != 0 {
			m[k].PayTime = gtime.New(item.PayTime).Format("Y-m-d H:i:s")
		} else {
			m[k].PayTime = ""
		}
	}

	return &model.RspList{
		List:  m,
		Total: int64(count),
	}, nil
}
